/**
 * 轮播图。和swiper.js的实现不同。这个插件完成轮播的功能，有一半的功劳要算在css上。
 * Methods
 * .carousel(options) {interval:number,pause:string,wrap:boolean,keyboard:boolean}
 * .carousel('cycle')
 * .carousel('pause')
 * .carousel(number)
 * .carousel('prev')
 * .carousel('next')
 */
(function($) {
    function Carousel(element, options) {
        this.$element = element
        this.$indicators = this.$element.find('.carousel-indicators')
        this.options = options
        this.paused = this.sliding = this.interval = this.$active = this.$items = null
        this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))
        this.options.pause == 'hover' && !('touchstart' in document.documentElement) && this.$element
            .on('mouseenter.bs.carousel', $.proxy(this.pause, this)) //注意mouseover和mouseenter的区别
            .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
    }

    Carousel.DEFAULTS = {
        interval: 5000,
        pause: 'hover',
        wrap: true, //这个有什么用？
        keyboard: true
    }

    Carousel.prototype = {
        constructor: Carousel,
        keydown: function(e) {
            switch (e.which) {
                case 37:
                    this.prev()
                    break
                case 39:
                    this.next()
                    break
            }
            e.preventDefault()
        },
        getItemIndex: function(item) {
            this.$items = item.parent().children('.item')
            return this.$items.index(item)
        },
        getItemForDirection: function(type, active) {
            var delta = type == 'prev' ? -1 : 1,
                activeIndex = this.getItemIndex(active)
            return this.$items.eq((activeIndex + delta) % this.$items.length)
        },
        slide: function(type, next) {
            var $active = this.$element.find('.item.active'),
                $next = next || this.getItemForDirection(type, $active),
                direction = type == 'next' ? 'left' : 'right',
                that = this

            //已经有了
            if ($next.hasClass('active')) {
                return
            }
            var slideEvent = $.Event('slide.bs.carousel', {
                relatedTarget: $next[0],
                direction: direction
            })

            //为何是$element来触发？
            this.$element.trigger(slideEvent)
            if (slideEvent.isDefaultPrevented()) {
                return
            }
            this.sliding = true

            //处理pagination
            if (this.$indicators.length) {
                this.$indicators.find('.active').removeClass('active')
                    .end().children().eq(this.getItemIndex($next))
                    .addClass('active')
            }
            var slidEvent = $.Event('slid.bs.carousel', {
                relatedTarget: $next[0],
                direction: direction
            })

            if ($.support.transition && this.$element.hasClass('slide')) {
                $next.addClass(type)
                $next[0].offsetWidth
                $next.addClass(direction)

                //只能用one
                $active.addClass(direction).one('bsTransitionEnd', function() {
                    $active.removeClass('active ' + direction)
                    $next.removeClass(direction + ' ' + type).addClass('active')
                    that.sliding = false
                    $active.trigger(slidEvent)
                })
            } else {
                $next.addClass('active')
                $active.removeClass('active')
                this.sliding = false
            }
            return this
        },
        to: function(num) {
            var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active')),
                that = this
            if (num < 0 || num > this.$items.length || num == activeIndex) {
                return
            }
            if (this.sliding) {
                return this.$element.one('slid.bs.carousel', function() {
                    that.to(num)
                })
            }
            this.slide(num < activeIndex ? 'prev' : 'next', this.$items.eq(num))
            return this
        },
        prev: function() {
            !this.sliding && this.slide('prev')
        },
        next: function() {
            !this.sliding && this.slide('next')
        },
        pause: function() {
            this.pause = true
            this.inteval = clearInterval(this.interval)
            return this
        },
        cycle: function(e) {
            this.paused = false
            this.interval && clearInterval(this.interval)
            if (this.options.interval) {
                this.interval = setInterval($.proxy(this.next, this), this.options.interval)
            }
            return this
        }
    }

    /**
     * Plugin就像一个启动控制装置，负责启动插件，通过插件执行某些功能
     */
    function Plugin(option) {
        return $(this).each(function() {
            var $this = $(this),
                options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option),
                action = typeof option == 'string' ? option : options.slide,
                data = $this.data('bs.carousel')
            if (!data) {
                $(this).data('bs.carousel', data = new Carousel($this, options))
            }
            if (typeof option == 'number') {
                data.to(option)
            } else if (action) {
                data[action]()
            } else if (options.interval) {
                //如果要轮播，立马开始，利用pause清除掉之前的interval
                data.cycle()
            }
        })
    }

    var origin = $.fn.carousel
    $.fn.carousel = Plugin
    $.fn.carousel.Constructor = Carousel
    $.fn.carousel.noConflict = function() {
        $.fn.carousel = origin
        return this
    }

    function clickHandler(e) {
        var $this = $(this),
            $target = $($this.data('target') || $this.attr('href'))
        if (!$target.hasClass('carousel')) {
            return
        }
        var options = $.extend({}, $target.data(), $this.data()),
            toIndex = $this.attr('data-slide-to')
        if (toIndex) {
            //为何这里要这样？感觉没这个必要
            options.interval = false
        }
        Plugin.call($target, options)
        if (toIndex) {
            $target.data('bs.carousel').to(toIndex)
        }
        e.preventDefault()
    }
    //有两种方式来创建carousel实例，一种是点击，另一种是页面加载完成后创建。
    $(document).on('click.bs.carousel.data-api', '[data-slide]', clickHandler)
        .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)

    $(window).load(function() {
        $('[data-ride="carousel"]').each(function() {
            var $carousel = $(this)
            Plugin.call($carousel, $carousel.data())
        })
    })
}(jQuery))

/**
 * 机智的css,不仅是因为transition属性。
 * active next prev，这3个类表示状态
 * left right，这2个类表示动作
 * 还有一个hack写法@media all and (transform-3d),(-webkit-transform-3d)  一看就知道是要排除不支持3d变化的浏览器，
 * 这里利用了.item.next的优先级要大于.item和.next这个条件，不然这段css不敢放在中间的位置。其实把这段css放到最后，
 * 就不用多加个item类了。
.carousel-inner {
    position: relative;
    width: 100%;
    overflow: hidden
}

.carousel-inner>.item {
    position: relative;
    display: none;
    -webkit-transition: .6s ease-in-out left;
    -o-transition: .6s ease-in-out left;
    transition: .6s ease-in-out left
}

.carousel-inner>.item>img,.carousel-inner>.item>a>img {
    line-height: 1
}

@media all and (transform-3d),(-webkit-transform-3d) {
    .carousel-inner>.item {
        -webkit-transition: -webkit-transform .6s ease-in-out;
        -o-transition: -o-transform .6s ease-in-out;
        transition: transform .6s ease-in-out;
        -webkit-backface-visibility: hidden;
        backface-visibility: hidden;
        -webkit-perspective: 1000;
        perspective: 1000
    }

    .carousel-inner>.item.next,.carousel-inner>.item.active.right {
        left: 0;
        -webkit-transform: translate3d(100%,0,0);
        transform: translate3d(100%,0,0)
    }

    .carousel-inner>.item.prev,.carousel-inner>.item.active.left {
        left: 0;
        -webkit-transform: translate3d(-100%,0,0);
        transform: translate3d(-100%,0,0)
    }

    .carousel-inner>.item.next.left,.carousel-inner>.item.prev.right,.carousel-inner>.item.active {
        left: 0;
        -webkit-transform: translate3d(0,0,0);
        transform: translate3d(0,0,0)
    }
}

.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev {
    display: block
}

.carousel-inner>.active {
    left: 0
}

.carousel-inner>.next,.carousel-inner>.prev {
    position: absolute;
    top: 0;
    width: 100%
}

.carousel-inner>.next {
    left: 100%
}

.carousel-inner>.prev {
    left: -100%
}

.carousel-inner>.next.left,.carousel-inner>.prev.right {
    left: 0
}

.carousel-inner>.active.left {
    left: -100%
}

.carousel-inner>.active.right {
    left: 100%
}
 */
